/******************************************************************************************************
Copyright (C) 2017 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/
/*globals FileDialog, qsTr, File, TextStream, Dir, serialization, molecule, NMRAssignments, nmr, Application, Str, mainWindow, settings, MessageBox, MnUi*/
/*jslint plusplus: true, indent: 4*/


function MagResImporter() {
	"use strict";
	this.ui = 0;
	this.structureData = [];
	this.appliedStructureData = [];
	this.nmrData = [];
	this.appliedNmrData = [];
	this.devFromTypicalBond = 0.1;
	this.calc_name = "";
	this.expSpectrum = {};
	this.synSpectrum = {};
	this.expPage = {};
	this.synPage = {};
	this.params = {
		nucleus : "1H",
		spectrumSize : 16384,
		fromPPM : -200.0,
		toPPM : 200.0,
		MHz : 500.0,
		LW : 30.0,
		ShieldingC : -100.0,
		ShieldingMult : -1.0,
		LoadMode : 1,
		AverageMode : 0,
		stackWithCurrent : false,
		loadStructure : false
	};
}

function importMagres() {

	"use strict";
	var fileName, file, workingDir = "", slist, line, importer;

	try {
		workingDir = settings.value(MagResImporter.cRegKey + "lastDir", "");
		fileName = FileDialog.getOpenFileName(qsTr("MagRes files (*.magres)"), "Select MagRes file", workingDir);
		if (!fileName.length) {
			return;
		}
		workingDir = File.absDirPath(fileName);
		settings.setValue(MagResImporter.cRegKey + "lastDir", workingDir);

		file = new File(fileName);
		//Check file
		if (!file.open(File.ReadOnly)) {
			throw new Error("The .magres file could not be opened");
		}

		importer = new MagResImporter();
		slist = new TextStream(file);

		do {
			line = slist.readLine();
			if (line.indexOf("[atoms]") > -1) {
				importer.readAtoms(slist);
			} else if (line.indexOf("[magres]") > -1) {
				importer.readNMR(slist);
			} else if (line.indexOf("calc_name") > -1) {
				importer.calc_name = line.slice(10);
			}
		} while (!slist.atEnd());
		file.close();

		importer.getParameters();

		if (Application.mainWindow.activeDocument === undefined || !Application.mainWindow.activeDocument.isValid()) {
			Application.mainWindow.newDocument();
		}
		if (importer.params.loadStructure) {
			importer.loadMol();
		}
		importer.createSpec();
		if (importer.params.loadStructure) {
			importer.createAssignments();
		}
		mainWindow.doAction("action_View_Zoom_FullSpec");
		if (importer.params.stackWithCurrent) {
			mainWindow.doAction("arrAutoScale");
		}
	} catch (err) {
		if (err.message !== "") {
			MessageBox.critical(err);
		}
		return;
	}
}

MagResImporter.prototype = {};
MagResImporter.cRegKey = "importMagRes/";

MagResImporter.prototype.readAtoms = function (slist) {
	"use strict";
	var line, entries, atomItem;

	do {
		line = slist.readLine();
		line = line.replace(/^\s+|\s+$/g, "");
		entries = line.split(/\s+/);
		if (entries[0] === "atom") {
			atomItem = {element: entries[1], label: entries[2], number: Number(entries[3]), x: Number(entries[4]), y: Number(entries[5]), z: Number(entries[6])};
			if (atomItem.label === atomItem.element) {
				atomItem.label = atomItem.label + atomItem.number;
			}
			this.structureData.push(atomItem);
		}
	} while (line.indexOf("[/atoms]") === -1);
};


MagResImporter.prototype.readNMR = function (slist) {
	"use strict";
	var line, entries, assigned, ppm, index, currentLabel;
	assigned = [];
	do {
		line = slist.readLine();
		line = line.replace(/^\s+|\s+$/g, "");
		entries = line.split(/\s+/);
		if (entries[0] === "ms") {
			currentLabel = entries[1];
			//check if entries[1] is just an element, not a proper label
			if (this.elementToNucleus(currentLabel).length > 0) {
				currentLabel += entries[2];
			}
			index = assigned.indexOf(currentLabel);
			if (index <= -1) {
				assigned.push(currentLabel);
				ppm = Number(entries[3]) + Number(entries[7]) + Number(entries[11]);
				ppm = ppm / 3.0;
				this.nmrData.push({label: currentLabel, shift: ppm, intensity: 1});
			} else {
				this.nmrData[index].intensity = this.nmrData[index].intensity + 1;
			}
		}
	} while (line.indexOf("[/magres]") === -1);
};

MagResImporter.prototype.isValid = function () {
	"use strict";
	var i, res;
	res = false;
	for (i = 0; i < this.structureData.length; i++) {
		if (this.structureData[i].label !== this.structureData[i].element) {
			res = true;
		}
	}
	return res;
};

MagResImporter.prototype.refineMol = function () {
	"use strict";
	var i, loadedLabels = [];
	this.appliedStructureData = [];
	if (this.params.LoadMode === 1) { //Select labels once
		for (i = 0; i < this.structureData.length; i++) {
			if (loadedLabels.indexOf(this.structureData[i].label) < 0) {
				loadedLabels.push(this.structureData[i].label);
				this.appliedStructureData.push(this.structureData[i]);
			}
		}
	} else {
		this.appliedStructureData = this.structureData;
	}
};

MagResImporter.prototype.loadMol = function () {
	"use strict";
	var filename, file, sout, i;

	if (mainWindow.activeDocument.curPage().itemCount() > 0) {
		mainWindow.activeDocument.newPage();
	}

	this.refineMol();

	filename = Dir.temp() + "/TempMol.mol";
	filename = Dir.convertSeparators(filename);

	file = new File(filename);
	//Check file
	if (!file.open(File.WriteOnly)) {
		throw new Error("Cannot open temporary .mol file for writing");
	}

	sout = new TextStream(file);
	sout.precision = 6;

	sout.writeln("Magres_molecule");
	sout.writeln("MRMESTRENV010116000000000000000000000000000000000000");
	sout.writeln(" ");

	sout.writeln(this.formatInt(this.appliedStructureData.length, 3), this.formatInt(this.reconstructBonds(0), 3), "  0  0  0  0            ", this.formatInt(this.appliedStructureData.length + 1, 3), " V2000");

	for (i = 0; i < this.appliedStructureData.length; i++) {
		sout.writeln(this.formatFloat(this.appliedStructureData[i].x), this.formatFloat(this.appliedStructureData[i].y), this.formatFloat(this.appliedStructureData[i].z), " ", this.formatStr(this.appliedStructureData[i].element, 3), " 0  0  0  0  0  0  0  0  0  0  0  0");
	}

	this.reconstructBonds(sout);

	for (i = 0; i < this.appliedStructureData.length; i++) {
		sout.writeln("M  ZZC", this.formatInt(i + 1, 4), " ", this.appliedStructureData[i].label);
	}

	sout.writeln("M END");
	file.close();
	serialization.open(filename);
	file.remove();
};

MagResImporter.prototype.createAssignments = function () {
	"use strict";
	var mol, spec, assign, i, j;

	mol = molecule.activeMolecule();
	assign = new NMRAssignments(mol);
	for (i = 0; i < this.appliedStructureData.length; i++) {
		for (j = 0; j < this.appliedNmrData.length; j++) {
			if (this.appliedStructureData[i].label === this.appliedNmrData[j].label) {
				assign.setChemShift(i + 1, 0, this.params.ShieldingC +  this.params.ShieldingMult * this.appliedNmrData[j].shift);
			}
		}
	}
	spec = nmr.activeSpectrum();
	spec.linkItems("Assignments", mol);
	mainWindow.doAction("nmrMoleculeShowAssignment");
};

MagResImporter.prototype.formatFloat = function (num) {
	"use strict";
	var str;
	str = num.toFixed(4);
	while (str.length < 10) {
		str = " " + str;
	}
	return str;
};

MagResImporter.prototype.formatInt = function (num, fields) {
	"use strict";
	var str;
	str = num.toString();
	while (str.length < fields) {
		str = " " + str;
	}
	return str;
};

MagResImporter.prototype.formatStr = function (str, fields) {
	"use strict";
	while (str.length < fields) {
		str = " " + str;
	}
	return str;
};

MagResImporter.prototype.getParameters = function () {
	"use strict";
	var powerOf2Items = [], showDialog, i, nucList = [], index;
	this.ui = Application.loadUiFile("ricares:importMagres.ui");
	if (this.ui === undefined) {
		throw new Error("Unable to load UI");
	}
	this.ui.widgets.fLoadModeCB.currentIndex = settings.value(MagResImporter.cRegKey + "LoadMode", 1);
	for (i = 1; i < 20; ++i) {
		powerOf2Items.push(Math.pow(2, i).toString());
	}
	this.ui.widgets.fPointComboBox.items = powerOf2Items;
	this.ui.widgets.fPointComboBox.currentIndex = settings.value(MagResImporter.cRegKey + "pointsPos", 13);
	this.params.nucleus = settings.value(MagResImporter.cRegKey + "nucleus", "1H");
	nucList = this.nucleiList();
	this.ui.widgets.fNucleusComboBox.items = nucList;
	index = nucList.indexOf(this.params.nucleus);
	if (index < 0) {
		index = 0;
	}
	this.ui.widgets.fNucleusComboBox.currentIndex = index;
	this.ui.widgets.fFromDoubleSpinBox.value = settings.value(MagResImporter.cRegKey + "fromPpm", this.params.fromPPM);
	this.ui.widgets.fToDoubleSpinBox.value = settings.value(MagResImporter.cRegKey + "toPpm", this.params.toPPM);
	this.ui.widgets.fMHzDoubleSpinBox.value = settings.value(MagResImporter.cRegKey + "MHz", this.params.MHz);
	this.ui.widgets.fLineWidthDoubleSpinBox.value = settings.value(MagResImporter.cRegKey + "LW", 30.0);
	this.ui.widgets.fAverageCB.currentIndex = settings.value(MagResImporter.cRegKey + "AverageMode", this.params.AverageMode);
	this.ui.widgets.fShieldValueSB.value = settings.value(MagResImporter.cRegKey + "ShieldingC", this.params.ShieldingC);
	this.ui.widgets.fShieldMultSB.value = settings.value(MagResImporter.cRegKey + "ShieldingMult", this.params.ShieldingMult);
	this.ui.widgets.fLoadStructureCB.checked = settings.value(MagResImporter.cRegKey + "LoadStructure", this.params.loadStructure);

	this.ui.widgets.fNucleusComboBox['currentIndexChanged(const QString&)'].connect(this, 'onUpdateDialog');
	this.ui.widgets.fShieldValueSB['valueChanged(double)'].connect(this, 'onUpdateDialog');
	this.ui.widgets.fShieldMultSB['valueChanged(double)'].connect(this, 'onUpdateDialog');
	this.ui.widgets.fAverageCB['currentIndexChanged(const QString&)'].connect(this, 'onUpdateDialog');
	this.ui.widgets.fFromDoubleSpinBox['valueChanged(double)'].connect(this, 'onUpdateDialog');
	this.ui.widgets.fToDoubleSpinBox['valueChanged(double)'].connect(this, 'onUpdateDialog');
	this.ui.widgets.fStackWithCurrentCB['toggled(bool)'].connect(this, 'onUpdateDialog');

	if (!nmr.activeSpectrum().isValid()) {
		this.ui.widgets.fStackWithCurrentCB.setEnabled(false);
	} else {
		if (nmr.activeSpectrum().dimCount !== 1) {
			this.ui.widgets.fStackWithCurrentCB.setEnabled(false);
		}
		if (nucList.indexOf(nmr.activeSpectrum().nucleus()) < 0) {
			this.ui.widgets.fStackWithCurrentCB.setEnabled(false);
		}
	}

	this.onUpdateDialog();
	this.ui.show();
	showDialog = true;

	while (showDialog) {
		if (!this.ui.exec()) {
			throw new Error("");
		}
		if (this.ui.widgets.fStackWithCurrentCB.checked) {
			this.expSpectrum = nmr.activeSpectrum();
			this.expPage = mainWindow.activeDocument.curPage();
			this.params.stackWithCurrent = true;
		}
		this.params.nucleus = this.ui.widgets.fNucleusComboBox.currentText;
		this.params.fromPPM = this.ui.widgets.fFromDoubleSpinBox.value;
		this.params.toPPM = this.ui.widgets.fToDoubleSpinBox.value;
		this.params.spectrumSize = parseInt(this.ui.widgets.fPointComboBox.currentText, 10);
		this.params.MHz = this.ui.widgets.fMHzDoubleSpinBox.value;
		this.params.LW = this.ui.widgets.fLineWidthDoubleSpinBox.value / this.isotopeToFreq(this.params.nucleus);
		this.params.AverageMode = this.ui.widgets.fAverageCB.currentIndex;
		this.params.ShieldingC = this.ui.widgets.fShieldValueSB.value;
		this.params.ShieldingMult = this.ui.widgets.fShieldMultSB.value;
		this.params.LoadMode = this.ui.widgets.fLoadModeCB.currentIndex;
		this.params.loadStructure = this.ui.widgets.fLoadStructureCB.checked;

		settings.setValue(MagResImporter.cRegKey + "nucleus", this.params.nucleus);
		settings.setValue(MagResImporter.cRegKey + "pointsPos", this.ui.widgets.fPointComboBox.currentIndex);
		settings.setValue(MagResImporter.cRegKey + "fromPpm", this.params.fromPPM);
		settings.setValue(MagResImporter.cRegKey + "toPpm", this.params.toPPM);
		settings.setValue(MagResImporter.cRegKey + "MHz", this.params.MHz);
		settings.setValue(MagResImporter.cRegKey + "LW", this.ui.widgets.fLineWidthDoubleSpinBox.value);
		settings.setValue(MagResImporter.cRegKey + "AverageMode", this.ui.widgets.fAverageCB.currentIndex);
		settings.setValue(MagResImporter.cRegKey + "ShieldingC", this.params.ShieldingC);
		settings.setValue(MagResImporter.cRegKey + "ShieldingMult", this.params.ShieldingMult);
		settings.setValue(MagResImporter.cRegKey + "LoadMode", this.params.LoadMode);
		settings.setValue(MagResImporter.cRegKey + "LoadStructure", this.params.loadStructure);

		showDialog = false;
	}
};

MagResImporter.prototype.createSpec = function () {
	"use strict";
	var fSpectrum, i, j, fPeaks = [], mnovapeaks, xml, h, s, w, finalPeaks = [], arrayedSpecs;

	fSpectrum = {
		nucleus: this.params.nucleus,
		from: this.params.fromPPM,
		to: this.params.toPPM,
		nPoints: this.params.spectrumSize,
		frequency: this.isotopeToFreq(this.params.nucleus),
		lineWidth: this.params.LW
	};

	this.appliedNmrData = this.selectPeaks(this.nucleusToElement(this.params.nucleus));

	if (this.appliedNmrData.length > 0) {
		for (i = 0; i < this.appliedNmrData.length; i++) {
			h = this.appliedNmrData[i].intensity;
			s = this.params.ShieldingC + this.params.ShieldingMult * this.appliedNmrData[i].shift;
			w = fSpectrum.lineWidth;
			fPeaks.push({'heigth': h, 'dim': [{'shift': s, 'width': w}]});
		}

		mnovapeaks = {'@version': '1.0', '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', '@xsi:noNamespaceSchemaLocation': 'Mnova-Peak.xsd', 'spectrum': {'dim': [fSpectrum], 'solvent': ''}, 'peakList': {'peak': fPeaks}};
		xml = Str.jsonToXML({'mnova-peaks': mnovapeaks});
		Application.nmr.syntheticPeaksSpectrum(xml);

		//add labels to the peaks
		finalPeaks = nmr.activeSpectrum().peaks();
		for (i = 0; i < finalPeaks.length; i++) {
			for (j = 0; j < this.appliedNmrData.length; j++) {
				if (Math.abs(this.params.ShieldingC + this.params.ShieldingMult * this.appliedNmrData[j].shift - finalPeaks.at(i).delta())  < 0.001) {
					finalPeaks.at(i).annotation = this.appliedNmrData[j].label;
				}
			}
		}
		nmr.activeSpectrum().setPeaks(finalPeaks);
		nmr.activeSpectrum().comment = this.calc_name;
		this.synSpectrum = nmr.activeSpectrum();
		this.synPage = mainWindow.activeDocument.curPage();

		if (this.params.stackWithCurrent) {
			arrayedSpecs = [];
			arrayedSpecs.push(this.expSpectrum);
			arrayedSpecs.push(this.synSpectrum);
			nmr.createArrayedItem(arrayedSpecs, true);
			mainWindow.activeDocument.deletePages(this.expPage);
			mainWindow.activeDocument.deletePages(this.synPage);
		}
	}
};

MagResImporter.prototype.selectPeaks = function (aElement) {
	"use strict";
	var i, res, item, element, X;
	res = [];
	for (i = 0; i < this.nmrData.length; i++) {
		element = this.labelToElement(this.nmrData[i].label);
		if (element === aElement) {
			//create a deep copy
			item = {label : this.nmrData[i].label,
					shift : this.nmrData[i].shift,
					intensity : this.nmrData[i].intensity};
			res.push(item);
		}
	}
	if (aElement === "H") {
		if (this.params.AverageMode > 0) { //AvarageMode=0 is "None"
			if (this.params.AverageMode === 1) { //AvarageMode=1 is "protons in CH3s"
				X = "C";
			} else {
				X = "X";
			}
			res = this.averageShifts(res, X);
		}
	}
	return res;
};

MagResImporter.prototype.labelToElement = function (label) {
	"use strict";
	var i;
	for (i = 0; i < this.structureData.length; i++) {
		if (this.structureData[i].label === label) {
			return this.structureData[i].element;
		}
	}
	return "";
};

MagResImporter.prototype.nucleiList = function () {
	"use strict";
	var elements = [], res = [], i, j, subset;
	for (i = 0; i < this.structureData.length; i++) {
		if (elements.indexOf(this.structureData[i].element) <= -1) {
			elements.push(this.structureData[i].element);
			subset = this.elementToNucleus(this.structureData[i].element);
			for (j = 0; j < subset.length; j++) {
				res.push(subset[j]);
			}
		}
	}
	return res;
};

MagResImporter.prototype.reconstructBonds = function (stream) {
	"use strict";
	var i, j, x, y, z, dist, nbonds, bond;
	nbonds = 0;
	for (i = 0; i < this.appliedStructureData.length - 1; i++) {
		for (j = i + 1; j < this.appliedStructureData.length; j++) {
			x = this.appliedStructureData[i].x - this.appliedStructureData[j].x;
			y = this.appliedStructureData[i].y - this.appliedStructureData[j].y;
			z = this.appliedStructureData[i].z - this.appliedStructureData[j].z;
			dist = Math.sqrt(x * x + y * y + z * z);
			bond = this.checkBond(this.appliedStructureData[i].element, this.appliedStructureData[j].element, dist);
			if (bond > -1) {
				nbonds++;
				if (stream) {
					stream.writeln(this.formatInt(i + 1, 3), this.formatInt(j + 1, 3), this.formatInt(bond, 3), "  0  0  0  0");
				}
			}
		}
	}
	return nbonds;
};

MagResImporter.prototype.elementToNucleus = function (aElement) {
	"use strict";
	var res = [], table, i;

	table = this.nmrTable();
	for (i = 0; i < table.length; i++) {
		if (this.nucleusToElement(table[i].Nucleus) === aElement) {
			res.push(table[i].Nucleus);
		}
	}
	return res;
};

MagResImporter.prototype.nucleusToElement = function (nucleus) {
	"use strict";
	var res;
	res = nucleus.replace(/\d+/g, '');
	return res;
};

MagResImporter.prototype.checkBond = function (atom1, atom2, dist) {
	"use strict";
	var table, i;

	table = [
		{ "atom1": "C", "atom2": "C", "length": 1.54, "type": 1 },
		{ "atom1": "N", "atom2": "N", "length": 1.45, "type": 1 },
		{ "atom1": "O", "atom2": "O", "length": 1.48, "type": 1 },
		{ "atom1": "C", "atom2": "N", "length": 1.47, "type": 1 },
		{ "atom1": "C", "atom2": "N", "length": 1.29, "type": 2 },
		{ "atom1": "C", "atom2": "N", "length": 1.16, "type": 3 },
		{ "atom1": "C", "atom2": "O", "length": 1.43, "type": 1 },
		{ "atom1": "C", "atom2": "O", "length": 1.20, "type": 2 },
		{ "atom1": "C", "atom2": "O", "length": 1.13, "type": 3 },
		{ "atom1": "H", "atom2": "C", "length": 1.09, "type": 1 },
		{ "atom1": "H", "atom2": "N", "length": 1.01, "type": 1 },
		{ "atom1": "H", "atom2": "O", "length": 0.96, "type": 1 },
		{ "atom1": "C", "atom2": "C", "length": 1.34, "type": 2 },
		{ "atom1": "C", "atom2": "C", "length": 1.20, "type": 3 },
		{ "atom1": "O", "atom2": "O", "length": 1.21, "type": 2 },
		{ "atom1": "N", "atom2": "N", "length": 1.10, "type": 3 },
		{ "atom1": "N", "atom2": "O", "length": 1.40, "type": 1 },
		{ "atom1": "N", "atom2": "O", "length": 1.21, "type": 2 }
	];

	for (i = 0; i < table.length; i++) {
		if ((atom1 === table[i].atom1 && atom2 === table[i].atom2) || (atom2 === table[i].atom1 && atom1 === table[i].atom2)) {
			if (Math.abs(dist - table[i].length) / table[i].length < this.devFromTypicalBond) {
				return table[i].type;
			}
		}
	}
	return -1;
};

MagResImporter.prototype.nmrTable = function () {
	"use strict";
	return [
		{ "Nucleus": "1H", "Freq": 750.03 },
		{ "Nucleus": "2H", "Freq": 115.13 },
		{ "Nucleus": "3He", "Freq": 800.01 },
		{ "Nucleus": "6Li", "Freq": 110.38 },
		{ "Nucleus": "7Li", "Freq": 291.51 },
		{ "Nucleus": "9Be", "Freq": 105.41 },
		{ "Nucleus": "11B", "Freq": 240.68 },
		{ "Nucleus": "10B", "Freq": 80.6 },
		{ "Nucleus": "13C", "Freq": 188.64 },
		{ "Nucleus": "14N", "Freq": 54.22 },
		{ "Nucleus": "15N", "Freq": 76.05 },
		{ "Nucleus": "17O", "Freq": 101.72 },
		{ "Nucleus": "19F", "Freq": 705.99 },
		{ "Nucleus": "21Ne", "Freq": 59.24 },
		{ "Nucleus": "23Na", "Freq": 198.51 },
		{ "Nucleus": "25Mg", "Freq": 45.95 },
		{ "Nucleus": "27Al", "Freq": 195.59 },
		{ "Nucleus": "29Si", "Freq": 149.13 },
		{ "Nucleus": "31P", "Freq": 303.9 },
		{ "Nucleus": "33S", "Freq": 57.62 },
		{ "Nucleus": "35Cl", "Freq": 73.57 },
		{ "Nucleus": "37Cl", "Freq": 61.24 },
		{ "Nucleus": "41K", "Freq": 0 },
		{ "Nucleus": "39K", "Freq": 35.05 },
		{ "Nucleus": "43Ca", "Freq": 50.54 },
		{ "Nucleus": "45Sc", "Freq": 182.49 },
		{ "Nucleus": "47Ti", "Freq": 42.35 },
		{ "Nucleus": "49Ti", "Freq": 42.36 },
		{ "Nucleus": "51V", "Freq": 197.17 },
		{ "Nucleus": "50V", "Freq": 74.74 },
		{ "Nucleus": "53Cr", "Freq": 42.26 },
		{ "Nucleus": "55Mn", "Freq": 185.56 },
		{ "Nucleus": "57Fe", "Freq": 24.25 },
		{ "Nucleus": "59Co", "Freq": 176.98 },
		{ "Nucleus": "61Ni", "Freq": 67.14 },
		{ "Nucleus": "65Cu", "Freq": 213.23 },
		{ "Nucleus": "63Cu", "Freq": 199.27 },
		{ "Nucleus": "67Zn", "Freq": 125.5 },
		{ "Nucleus": "71Ga", "Freq": 229.37 },
		{ "Nucleus": "69Ga", "Freq": 180.52 },
		{ "Nucleus": "73Ge", "Freq": 26.24 },
		{ "Nucleus": "75As", "Freq": 128.86 },
		{ "Nucleus": "77Se", "Freq": 143.58 },
		{ "Nucleus": "79Br", "Freq": 188.56 },
		{ "Nucleus": "81Br", "Freq": 203.26 },
		{ "Nucleus": "83Kr", "Freq": 28.96 },
		{ "Nucleus": "87Rb", "Freq": 245.4 },
		{ "Nucleus": "85Rb", "Freq": 72.41 },
		{ "Nucleus": "87Sr", "Freq": 32.62 },
		{ "Nucleus": "89Y", "Freq": 36.74 },
		{ "Nucleus": "91Zr", "Freq": 70.02 },
		{ "Nucleus": "93Nb", "Freq": 184.12 },
		{ "Nucleus": "97Mo", "Freq": 50.14 },
		{ "Nucleus": "95Mo", "Freq": 49.09 },
		{ "Nucleus": "99Ru", "Freq": 33.43 },
		{ "Nucleus": "101Ru", "Freq": 37.46 },
		{ "Nucleus": "103Rh", "Freq": 23.74 },
		{ "Nucleus": "105Pd", "Freq": 34.37 },
		{ "Nucleus": "107Ag", "Freq": 30.51 },
		{ "Nucleus": "109Ag", "Freq": 35.15 },
		{ "Nucleus": "111Cd", "Freq": 159.85 },
		{ "Nucleus": "113Cd", "Freq": 167.23 },
		{ "Nucleus": "113In", "Freq": 164.98 },
		{ "Nucleus": "115In", "Freq": 165.33 },
		{ "Nucleus": "117Sn", "Freq": 268.83 },
		{ "Nucleus": "119Sn", "Freq": 281.25 },
		{ "Nucleus": "115Sn", "Freq": 246.76 },
		{ "Nucleus": "121Sb", "Freq": 180.67 },
		{ "Nucleus": "123Sb", "Freq": 97.86 },
		{ "Nucleus": "123Te", "Freq": 197.87 },
		{ "Nucleus": "125Te", "Freq": 238.56 },
		{ "Nucleus": "127I", "Freq": 151.1 },
		{ "Nucleus": "131Xe", "Freq": 61.93 },
		{ "Nucleus": "129Xe", "Freq": 208.93 },
		{ "Nucleus": "133Cs", "Freq": 99.08 },
		{ "Nucleus": "135Ba", "Freq": 75.04 },
		{ "Nucleus": "137Ba", "Freq": 83.94 },
		{ "Nucleus": "139La", "Freq": 106.78 },
		{ "Nucleus": "138La", "Freq": 99.74 },
		{ "Nucleus": "141Pr", "Freq": 214.84 },
		{ "Nucleus": "143Nd", "Freq": 41.3 },
		{ "Nucleus": "145Nd", "Freq": 25.51 },
		{ "Nucleus": "147Sm", "Freq": 31.18 },
		{ "Nucleus": "149Sm", "Freq": 25.71 },
		{ "Nucleus": "153Eu", "Freq": 82.37 },
		{ "Nucleus": "151Eu", "Freq": 186.51 },
		{ "Nucleus": "157Gd", "Freq": 30.25 },
		{ "Nucleus": "155Gd", "Freq": 23.14 },
		{ "Nucleus": "159Tb", "Freq": 180.2 },
		{ "Nucleus": "161Dy", "Freq": 25.38 },
		{ "Nucleus": "163Dy", "Freq": 35.72 },
		{ "Nucleus": "165Ho", "Freq": 160.06 },
		{ "Nucleus": "167Er", "Freq": 21.73 },
		{ "Nucleus": "169Tm", "Freq": 62.57 },
		{ "Nucleus": "173Yb", "Freq": 36.52 },
		{ "Nucleus": "171Yb", "Freq": 132.73 },
		{ "Nucleus": "175Lu", "Freq": 85.86 },
		{ "Nucleus": "179Hf", "Freq": 19.12 },
		{ "Nucleus": "181Ta", "Freq": 90.94 },
		{ "Nucleus": "183W", "Freq": 31.63 },
		{ "Nucleus": "187Re", "Freq": 172.92 },
		{ "Nucleus": "185Re", "Freq": 171.18 },
		{ "Nucleus": "187Os", "Freq": 17.6 },
		{ "Nucleus": "189Os", "Freq": 65.53 },
		{ "Nucleus": "191Ir", "Freq": 13.02 },
		{ "Nucleus": "193Ir", "Freq": 14.37 },
		{ "Nucleus": "195Pt", "Freq": 163.68 },
		{ "Nucleus": "197Au", "Freq": 13.15 },
		{ "Nucleus": "201Hg", "Freq": 50.15 },
		{ "Nucleus": "199Hg", "Freq": 135.86 },
		{ "Nucleus": "205Tl", "Freq": 439.81 },
		{ "Nucleus": "203Tl", "Freq": 435.66 },
		{ "Nucleus": "207Pb", "Freq": 157.75 },
		{ "Nucleus": "177Hf", "Freq": 30.44 },
		{ "Nucleus": "209Bi", "Freq": 125.95 },
		{ "Nucleus": "229Th", "Freq": 21.48 },
		{ "Nucleus": "235U", "Freq": 13.43 }
	];
};


MagResImporter.prototype.isotopeToFreq = function (aNucleus) {
	"use strict";
	var table, i;
	table = this.nmrTable();
	for (i = 0; i < table.length; i++) {
		if (table[i].Nucleus === aNucleus) {
			return this.params.MHz / table[0].Freq * table[i].Freq;
		}
	}
	return 100.0;
};

MagResImporter.prototype.equalArrays = function (a, b) {
	"use strict";
	var i;
	if (a.length !== b.length) {
		return false;
	}
	for (i = 0; i < a.length; i++) {
		if (a[i] !== b[i]) {
			return false;
		}
	}
	return true;
};

MagResImporter.prototype.labelsToAverage = function (X) {
	"use strict";
	var i, q, toAdd, res = [], connected = [];
	for (i = 0; i < this.appliedStructureData.length; i++) {
		connected = [];
		if (X === "X") {
			if (this.appliedStructureData[i].element !== "H") {
				connected = this.findConnectedHs(this.appliedStructureData[i]);
			}
		} else {
			if (X === this.appliedStructureData[i].element) {
				connected = this.findConnectedHs(this.appliedStructureData[i]);
			}
		}
		if (connected.length === 3) { //consider only XH3 groups
			connected.sort();
			//check for duplicates
			toAdd = true;
			for (q = 0; q < res.length; q++) {
				if (this.equalArrays(res[q], connected)) {
					toAdd = false;
				}
			}
			if (toAdd) {
				res.push(connected);
			}
		}
	}
	return res;
};

MagResImporter.prototype.findConnectedHs = function (atom) {
	"use strict";
	var i, res = [], x, y, z, dist;
	for (i = 0; i < this.appliedStructureData.length; i++) {
		if (this.appliedStructureData[i].element === "H") {
			x = this.appliedStructureData[i].x - atom.x;
			y = this.appliedStructureData[i].y - atom.y;
			z = this.appliedStructureData[i].z - atom.z;
			dist = Math.sqrt(x * x + y * y + z * z);
			if (this.checkBond(atom.element, this.appliedStructureData[i].element, dist) === 1) {
				res.push(this.appliedStructureData[i].label);
			}
		}
	}
	return res;
};

MagResImporter.prototype.averageShifts = function (peaks, X) {
	"use strict";
	var labels = [], indexes = [], i, p, q, avShift, sumInt;
	labels = this.labelsToAverage(X);
	for (i = 0; i < labels.length; i++) { //for each averaging combination
		indexes = [];
		avShift = 0.0;
		sumInt = 0.0;
		//Find peaks for the given combination
		for (p = 0; p < peaks.length; p++) {
			if (labels[i].indexOf(peaks[p].label) >= 0) {
				indexes.push(p);
			}
		}
		for (q = 0; q < indexes.length; q++) {
			avShift += peaks[indexes[q]].shift;
			sumInt += peaks[indexes[q]].intensity;
		}
		avShift /= indexes.length;
		for (q = 0; q < indexes.length; q++) {
			peaks[indexes[q]].shift = avShift;
			peaks[indexes[q]].intensity = sumInt;
		}
	}
	return peaks;
};

MagResImporter.prototype.onUpdateDialog = function () {
	"use strict";
	var peaksForNuc = [], i, max, min, shift, rangeWarning = false, index, table, limits;

	if (this.ui.widgets.fStackWithCurrentCB.checked) {
		index = this.ui.widgets.fNucleusComboBox.items.indexOf(nmr.activeSpectrum().nucleus());
		if (index >= 0) {
			this.ui.widgets.fNucleusComboBox.currentIndex = index;
		}
		index = 0;
		while (index < this.ui.widgets.fPointComboBox.items.length && nmr.activeSpectrum().count() > Number(this.ui.widgets.fPointComboBox.items[index])) {
			index++;
		}
		this.ui.widgets.fPointComboBox.currentIndex = index;

		table = this.nmrTable();
		for (i = 0; i < table.length; i++) {
			if (table[i].Nucleus === nmr.activeSpectrum().nucleus()) {
				this.ui.widgets.fMHzDoubleSpinBox.value = nmr.activeSpectrum().frequency() / table[i].Freq * table[0].Freq;
			}
		}
		limits = nmr.activeSpectrum().getFullScaleLimits();
		this.ui.widgets.fFromDoubleSpinBox.value = limits.fromX;
		this.ui.widgets.fToDoubleSpinBox.value = limits.toX;
		this.ui.widgets.specFrame.setEnabled(false);
	} else {
		this.ui.widgets.specFrame.setEnabled(true);
	}

	if (this.nucleusToElement(this.ui.widgets.fNucleusComboBox.currentText) === "H") {
		this.ui.widgets.fAverageCB.setEnabled(true);
	} else {
		this.ui.widgets.fAverageCB.setEnabled(false);
	}

	this.params.AverageMode = this.ui.widgets.fAverageCB.currentIndex;
	this.refineMol();
	peaksForNuc = this.selectPeaks(this.nucleusToElement(this.ui.widgets.fNucleusComboBox.currentText));

	max = -1e38;
	min = 1e38;
	for (i = 0; i < peaksForNuc.length; i++) {
		shift = this.ui.widgets.fShieldValueSB.value + this.ui.widgets.fShieldMultSB.value * peaksForNuc[i].shift;
		if (shift > max) {
			max = shift;
		}
		if (shift < min) {
			min = shift;
		}
	}
	if ((this.ui.widgets.fFromDoubleSpinBox.value > min) || (this.ui.widgets.fToDoubleSpinBox.value < max)) {
		rangeWarning = true;
	}
	this.ui.widgets.fRangeLb.text = "";
	if (rangeWarning) {
		this.ui.widgets.fRangeLb.text = '<span style=" color:#ff0000;"><b>WARNING: ';
	}
	this.ui.widgets.fRangeLb.text += "Peaks are in the range: " + min.toFixed(1) + " ppm to " + max.toFixed(1) + " ppm";
	if (rangeWarning) {
		this.ui.widgets.fRangeLb.text += "</b></span>";
	}
};

if (this.MnUi && MnUi.scripts_nmr) {
	MnUi.scripts_nmr.scripts_nmr_ImportMagres = importMagres;
}
